// ==UserScript==
// @name         ai对话历史快捷查询追溯
// @namespace    https://bbs.tampermonkey.net.cn/
// @version      0.1.0
// @description  解决单个对话太长，难以追溯之前的问答的问题，提供对历史问题的快捷寻找
// @author       口吃者
// @match        https://yuanbao.tencent.com/*
// @match        https://tongyi.aliyun.com/*
// @match        https://kimi.moonshot.cn/*
// @match        https://chat.deepseek.com/*
// @require      https://scriptcat.org/lib/2691/1.0.0/sweetalert2.all.min-11.15.10.js
// @run-at       document-end
// @license MIT
// ==/UserScript==

(function () {
    'use strict';

    const questionSelectorOption = {
        'yuanbao': '[data-conv-speaker="human"]',
        'tongyi': '.questionItem--dS3Alcnv',
        'kimi': '.user-content',
        'deepseek': '.fbb737a4'
    };

    const url = window.location.href;
    var questionSelector;
    if(url.includes('yuanbao')){
        questionSelector = questionSelectorOption['yuanbao'];
    }else if(url.includes('tongyi')){
        questionSelector = questionSelectorOption['tongyi'];
    }else if(url.includes('kimi')){
        questionSelector = questionSelectorOption['kimi'];
    }else if(url.includes('deepseek')){
        questionSelector = questionSelectorOption['deepseek'];
    }

    window.addEventListener('load', addPanel);

    // 辅助函数：平滑滚动到元素中心点
    function scrollToElement(element) {
        return new Promise((resolve) => {
            element.scrollIntoView({ behavior: 'smooth', block: 'center' });
            // 等待滚动动画完成
            setTimeout(resolve, 500); // 假设滚动动画持续时间不超过500ms
        });
    }
    /**
     * 根据选择器提取文本内容并裁剪到最大字符限制，并添加序号前缀
     * @param {string} selector - CSS选择器字符串
     * @param {number} maxChars - 每个提示项的最大字符数
     * @returns {string[]} 裁剪后的提示项数组（带序号前缀且去除多余空格）
     */
    function getTrimmedSuggestions(selector, maxChars) {
        // 参数验证
        if (typeof selector !== 'string' || selector.trim() === '') {
            throw new Error('Invalid selector: must be a non-empty string');
        }
        if (typeof maxChars !== 'number' || maxChars < 1) {
            throw new Error('Max chars must be a positive integer ≥1');
        }

        // 获取所有匹配元素并裁剪文本
        const elements = document.querySelectorAll(selector);
        const suggestions = [];

        elements.forEach(element => {
            // 新增：处理换行符和多余空格
            const rawText = element.textContent;
            const cleanedText = rawText
                .replace(/[\r\n]+/g, ' ') // 替换换行符为空格
                .replace(/\s+/g, ' ')     // 合并连续空格
                .trim();                  // 移除首尾空格

            if (cleanedText.length === 0) return; // 跳过空文本

            // 裁剪逻辑
            let trimmedText = cleanedText;
            if (cleanedText.length > maxChars) {
                trimmedText = cleanedText.slice(0, maxChars);
                // 可选：添加省略号（根据需求选择是否开启）
                // trimmedText += '...';
            }

            suggestions.push(trimmedText);
        });

        // 添加序号前缀
        const result = [];
        const len = suggestions.length;
        for (let i = 0; i < len; i++) {
            const index = -(len - 1 - i);
            const prefix = `${index}：`; // 中文冒号
            result.push(`${prefix}${suggestions[i]}`);
        }

        return result;
    }

    function addPanel() {
        function genButton(text, foo, id, fooParams = {}) {
            let b = document.createElement('button');
            b.textContent = text;
            b.style.verticalAlign = 'inherit';
            // 使用箭头函数创建闭包来保存 fooParams 并传递给 foo
            b.addEventListener('click', () => {
                foo.call(b, ...Object.values(fooParams)); // 使用 call 方法确保 this 指向按钮对象
            });
            if (id) { b.id = id };
            return b;
        }

        function changeRangeDynamics() {
            const value = parseInt(this.value, 10);
            // 只能通过 DOM 方法改变
            document.querySelector('#swal-range > output').textContent = value;
        }

        async function openPanelFunc() {
            var swalRangeValue = 0;
            // const promptArray = ["JavaScript框架", "React组件", "Vue开发"];
            const { value: formValues } = await Swal.fire({
                position: "center-end",
                draggable: true,
                backdrop: false,
                title: "<strong>Jump Location</strong>",
                showCancelButton: true,
                cancelButtonText: 'Cancel',
                confirmButtonText: 'Jump',
                //class="swal2-range" swalalert框架可能会对其有特殊处理，导致其内标签的id声明失效
                html: `
                  <input id="swal-input1" class="swal2-input" placeholder="输入关键词...">
                  <div id="suggestion-list" class="suggestion-list"></div>
                  <div class="swal2-range" id="swal-range" style="display: flex;">
                    <input type="range" min="-25" max="0" step="1" value="0">
                    <output>${swalRangeValue}</output>
                  </div>
                `,
                focusConfirm: false,
                didOpen: () => {
                    const swalRange = document.querySelector('#swal-range input');
                    const input = document.getElementById("swal-input1");
                    const suggestionList = document.getElementById("suggestion-list");
                    const promptArray = getTrimmedSuggestions(questionSelector, 16);
                    // 绑定输入事件
                    input.addEventListener("input", function () {
                        const query = this.value.trim().toLowerCase();
                        const filtered = query
                            ? promptArray.filter((item) =>
                                item.toLowerCase().includes(query)
                            )
                            : promptArray;
                        // 渲染提示项（无需单独绑定事件）
                        suggestionList.innerHTML = filtered
                            .map((item) => `<div class="suggestion-item">${item}</div>`)
                            .join("") || "<div class='no-result'>无匹配项</div>";
                        // suggestionList.style.display = filtered.length > 0 ? "block" : "none";
                        suggestionList.style.display = "block";
                    });

                    // 使用事件委托处理点击
                    suggestionList.addEventListener("click", (e) => {
                        const target = e.target;
                        if (target.classList.contains("suggestion-item")) {
                            e.preventDefault();
                            input.value = target.textContent;
                            const serialNumber = target.textContent.split('：')[0];
                            //同步更新序号选择器
                            document.querySelector('#swal-range > output').textContent = parseInt(serialNumber);
                            suggestionList.style.display = "none";
                        }
                    });

                    // 移除全局点击事件（原代码中的全局监听器已优化）
                    // 不需要额外处理，因为事件委托已足够
                    swalRange.addEventListener('input', changeRangeDynamics);
                },
                willClose: () => {
                    // 在关闭前清除事件监听器以防止内存泄漏
                    const swalRange = document.querySelector('#swal-range input');
                    swalRange.removeEventListener('input', changeRangeDynamics);
                },
                preConfirm: () => {
                    swalRangeValue = document.querySelector('#swal-range > output').textContent;
                    return [
                        parseInt(swalRangeValue)
                    ];
                }
            });
            if (formValues) {
                const humanArray = document.querySelectorAll(questionSelector);
                const targetSerial = humanArray.length + formValues[0] - 1;
                if(targetSerial < 0){
                    return;
                }
                scrollToElement(humanArray[targetSerial]);
            }
        }

        let myButton = genButton('History', openPanelFunc, 'History');
        document.body.appendChild(myButton);

        var css_text = `
        #History {
            position: fixed;
            color: #FF6B35; /* 橙色活力主题主色 */
            top: 70%;
            right: -20px; /* 初始右侧隐藏 */
            transform: translateY(-50%);
            z-index: 1000;
            padding: 10px 24px;
            border-radius: 5px;
            cursor: pointer;
            border: 0;
            background-color: white;
            box-shadow: rgba(0 0 0 / 5%) 0 0 8px;
            letter-spacing: 1.5px;
            text-transform: uppercase;
            font-size: 9px;
            transition: all 0.5s ease;
        }
        #History:hover {
            right: 0%; /* 鼠标悬停时完整显示 */
            letter-spacing: 3px;
            background-image: linear-gradient(to top, #FFD700 0%, #FFA080 100%); /* 橙色渐变 */
            box-shadow: rgba(255, 107, 0, 0.7) 0px 7px 29px 0px; /* 橙色阴影 */
        }
        
        #History:active {
            letter-spacing: 3px;
            background-image: linear-gradient(to top, #FFD700 0%, #FFA080 100%);
            box-shadow: rgba(255, 107, 0, 0.5) 0px 0px 0px 0px;
            transition: 100ms;
        }

        /* 提示列表容器 */
        .suggestion-list {
        margin-top: 8px;
        padding: 8px;
        background: white;
        border: 1px solid #ddd;
        border-radius: 4px;
        max-height: 150px;
        overflow-y: auto;
        display: none;
        }

        /* 单个提示项 */
        .suggestion-item {
        display: flex;
        align-items: center;
        padding: 6px 12px;
        cursor: pointer; /* 默认显示为可点击 */
        transition: background-color 0.3s ease; /* 平滑过渡效果 */
        }

        /* 悬停时的样式 */
        .suggestion-item:hover {
        background-color: #f0f0f0; /* 浅灰色背景 */
        cursor: pointer; /* 强调点击效果 */
        }

        /* 无匹配项的样式 */
        .no-result {
        padding: 6px 12px;
        color: #888;
        text-align: center;
        }
        `;
        GMaddStyle(css_text);
    }

    function GMaddStyle(css) {
        var myStyle = document.createElement('style');
        myStyle.textContent = css;
        var doc = document.head || document.documentElement;
        doc.appendChild(myStyle);
    }
})();